package com.xazenith.app;

import org.apache.commons.io.FileUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Objects;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @author zhou wei
 * @version 0.1
 * @since 2020-11-12
 */
public class Application {

    private static Logger logger = Logger.getLogger("application");

    /**
     * 默认的加密解密方法
     */
    private static final String DEFAULT_ENCODE_TYPE = "base64";


    public static void main(String... args) throws IOException, GeneralSecurityException {

        String encodeType = DEFAULT_ENCODE_TYPE;

        if(Objects.nonNull(args) && args.length > 0) {
            int i = 0;
            while (i < args.length) {
                String arg = args[i];
                if (Objects.equals(arg, "-method")) {
                    if (i + 1 < args.length) {
                        encodeType = args[i + 1];
                    } else {
                        throw new IllegalArgumentException("method need to be 'aes' , 'base64' ");
                    }
                }
                i++;
            }
        }

        switch(encodeType) {
            case "base64":
                logger.info("test encode decode use base64.");
                base64EncodeTest();
                base64DecodeTest();
                return;
            default:
                logger.info("test encode decode use aes 128 bit.");
                encodeTest();
                decodeTest();
        }
    }

    /**
     * BASE 64 加密测试
     */
    public static void base64EncodeTest() throws IOException {
        String path = "./demoData";
        File folder = new File(path);
        if (!folder.exists()) {
            File file = new File("./");
            throw new RuntimeException("could not found path: " + folder.getAbsolutePath() + ". current file path is: " + file.getAbsolutePath());
        }
        String target = "./encode/base64";
        File targetFile = new File(target);
        if (!targetFile.exists()) {
            FileUtils.forceMkdirParent(targetFile);
        } else {
            if(targetFile.delete()) {
                FileUtils.forceMkdirParent(targetFile);
            }
        }
        Zipper zipper = new Zipper(folder);
        targetFile.createNewFile();
        ByteArrayOutputStream ot = new ByteArrayOutputStream();
        zipper.zip(ot);
        byte[] encode = Base64EncodeUtil.encode(ot.toByteArray());
        FileUtils.writeByteArrayToFile(targetFile, encode);
    }

    /**
     * BASE 64 解密测试
     */
    public static void base64DecodeTest() throws IOException {
        String path = "./encode/base64";
        File encodeFile = new File(path);
        if (!encodeFile.exists()) {
            throw new RuntimeException("could not found encoded file: " + path);
        }
        String decodePath = "./encode/base64Decode";
        byte[] bytes = FileUtils.readFileToByteArray(encodeFile);
        byte[] decode = Base64EncodeUtil.decode(bytes);
        File targetFolder = new File(decodePath);
        if (!targetFolder.exists()) {
            FileUtils.forceMkdir(targetFolder);
        }
        FileUtils.writeByteArrayToFile(new File("./encode/base64Decode/base64Decode.zip"), decode);
        ZipInputStream zi = new ZipInputStream(new ByteArrayInputStream(decode));
        ZipEntry zen;
        while ((zen = zi.getNextEntry()) != null) {
            if (!zen.isDirectory()) {
                File nFile = new File(targetFolder.getAbsolutePath()  + "/" + zen.getName());
                FileUtils.forceMkdirParent(nFile);
                if (nFile.exists()) {
                    FileUtils.forceDelete(nFile);
                }
                nFile.createNewFile();
                zi.closeEntry();
            }
        }
        zi.close();
    }

    public static void encodeTest() throws IOException, GeneralSecurityException {
        String path = "./demoData";
        File folder = new File(path);
        if (!folder.exists()) {
            throw new RuntimeException("could not found path: " + path);
        }
        encodeFolder(folder, "./encode/aes/res");
    }

    public static void decodeTest() throws IOException, GeneralSecurityException {
        String path = "./encode/aes/res";
        File encodeFile = new File(path);
        if (!encodeFile.exists()) {
            throw new RuntimeException("could not found encoded file: " + path);
        }
        doDecode(encodeFile, "./encode/aesDecode");
    }

    public static void doDecode(File source, String target) throws IOException, GeneralSecurityException {
        byte[] bytes = FileUtils.readFileToByteArray(source);
        AesEncoder encoder = new AesEncoder("110101332");
        byte[] decode = encoder.decode(bytes);
        FileUtils.writeByteArrayToFile(new File("./encode/aesDecode/decoded.zip"), decode);
        ZipInputStream zi = new ZipInputStream(new ByteArrayInputStream(decode));

        File targetFolder = new File(target);
        if (!targetFolder.exists()) {
            FileUtils.forceMkdir(targetFolder);
        }

        ZipEntry zen;
        while ((zen = zi.getNextEntry()) != null) {
            if (!zen.isDirectory()) {
                File nFile = new File(targetFolder.getAbsolutePath()  + "/" + zen.getName());
                FileUtils.forceMkdirParent(nFile);
                if (nFile.exists()) {
                    FileUtils.forceDelete(nFile);
                }
                nFile.createNewFile();
                zi.closeEntry();
            }
        }
        zi.close();
    }

    public static void encodeFolder(File file, String target) throws IOException, GeneralSecurityException {
        Zipper zipper = new Zipper(file);
        File targetFile = new File(target);
        if (!targetFile.exists()) {
            FileUtils.forceMkdirParent(targetFile);
        } else {
            targetFile.delete();
        }
        targetFile.createNewFile();
        ByteArrayOutputStream ot = new ByteArrayOutputStream();
        zipper.zip(ot);
        AesEncoder encoder = new AesEncoder("110101332");
        byte[] encode = encoder.encode(ot.toByteArray());
        FileUtils.writeByteArrayToFile(targetFile, encode);
    }
}
